package com.skivingcloud.report.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Sets;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.skivingcloud.common.exceptions.BusinessException;
import com.skivingcloud.report.dto.DataSetParamDto;
import com.skivingcloud.report.entity.ReportDataSetParam;
import com.skivingcloud.report.mapper.ReportDataSetParamMapper;
import com.skivingcloud.report.service.ReportDataSetParamService;
import com.skivingcloud.report.utils.AnalysisUtil;
import org.apache.commons.lang3.StringUtils;
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
import org.springframework.stereotype.Service;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.skivingcloud.common.utils.PageParameter;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 数据集查询参数 服务层实现。
 *
 * @author skivingcloud
 * @since 2024-09-12
 */
@Service
public class ReportDataSetParamServiceImpl extends ServiceImpl<ReportDataSetParamMapper, ReportDataSetParam> implements ReportDataSetParamService {

    static final Set<String> blackList = Sets.newHashSet("java.lang.ProcessBuilder", "java.lang.Runtime", "java.lang.ProcessImpl");
    private static final ThreadLocal<ScriptEngine> engineHolder = ThreadLocal.withInitial(() -> {
        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
        return factory.getScriptEngine(clz -> !blackList.contains(clz));
    });
    public static ScriptEngine getEngine() {
        return engineHolder.get();
    }

    /**
     * 分页查询数据集查询参数
     *
     * @param parameter 查询参数
     * @return 分页查询结果
     */
    @Override
    public Page<ReportDataSetParam> queryByPage(PageParameter<ReportDataSetParam> parameter){
        Page<ReportDataSetParam> page = new Page<>(parameter.getPage(), parameter.getPageSize());
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (parameter.getParam() != null) {
            //查询条件
            if (StringUtils.isNoneBlank(parameter.getParam().getId())) {
                queryWrapper.and(ReportDataSetParam::getId).like(parameter.getParam().getId());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getSetCode())) {
                queryWrapper.and(ReportDataSetParam::getSetCode).like(parameter.getParam().getSetCode());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getParamName())) {
                queryWrapper.and(ReportDataSetParam::getParamName).like(parameter.getParam().getParamName());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getParamDesc())) {
                queryWrapper.and(ReportDataSetParam::getParamDesc).like(parameter.getParam().getParamDesc());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getParamType())) {
                queryWrapper.and(ReportDataSetParam::getParamType).like(parameter.getParam().getParamType());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getSampleItem())) {
                queryWrapper.and(ReportDataSetParam::getSampleItem).like(parameter.getParam().getSampleItem());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getEnableFlag())) {
                queryWrapper.and(ReportDataSetParam::getEnableFlag).like(parameter.getParam().getEnableFlag());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getDeleteFlag())) {
                queryWrapper.and(ReportDataSetParam::getDeleteFlag).like(parameter.getParam().getDeleteFlag());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getCreateBy())) {
                queryWrapper.and(ReportDataSetParam::getCreateBy).like(parameter.getParam().getCreateBy());
            }
            if (StringUtils.isNoneBlank(parameter.getParam().getUpdateBy())) {
                queryWrapper.and(ReportDataSetParam::getUpdateBy).like(parameter.getParam().getUpdateBy());
            }
        }
        return this.page(page, queryWrapper);
    }

    /**
     * 参数校验  js脚本
     *
     * @param dataSetParamDto 参数
     * @return 校验结果
     */
    @Override
    public Object verification(DataSetParamDto dataSetParamDto) {
        String validationRules = dataSetParamDto.getValidationRules();
        if (StringUtils.isNotBlank(validationRules)) {
            try {
                ScriptEngine engine = getEngine();
                engine.eval(validationRules);
                if(engine instanceof Invocable invocable){
                    Object exec = invocable.invokeFunction("verification", dataSetParamDto);
                    ObjectMapper objectMapper = new ObjectMapper();
                    if (exec instanceof Boolean) {
                        return objectMapper.convertValue(exec, Boolean.class);
                    }else {
                        return objectMapper.convertValue(exec, String.class);
                    }
                }

            } catch (Exception ex) {
                throw new BusinessException(ex.getMessage());
            }

        }
        return true;
    }

    /**
     * 参数校验  js脚本
     *
     * @param dataSetParamDtoList 参数
     * @param contextData 参数
     * @return 校验结果
     */
    @Override
    public boolean verification(List<DataSetParamDto> dataSetParamDtoList, Map<String, Object> contextData) {
        if (null == dataSetParamDtoList || dataSetParamDtoList.isEmpty()) {
            return true;
        }

        for (DataSetParamDto dataSetParamDto : dataSetParamDtoList) {
            if (null != contextData) {
                String value = contextData.getOrDefault(dataSetParamDto.getParamName(), "").toString();
                dataSetParamDto.setSampleItem(value);
            }

            Object verification = verification(dataSetParamDto);
            if (verification instanceof Boolean) {
                if (!(Boolean) verification) {
                    return false;
                }
            }else {
                //将得到的值重新赋值给contextData
                if (null != contextData) {
                    contextData.put(dataSetParamDto.getParamName(), verification);
                }
                dataSetParamDto.setSampleItem(verification.toString());
            }

        }
        return true;
    }

    /**
     * 参数替换
     *
     * @param dataSetParamDtoList 参数
     * @param dynSentence         查询
     * @return 结果
     */
    @Override
    public String transform(List<DataSetParamDto> dataSetParamDtoList, String dynSentence) {
        Map<String, Object> contextData = new HashMap<>();
        if (null == dataSetParamDtoList || dataSetParamDtoList.isEmpty()) {
            return dynSentence;
        }
        dataSetParamDtoList.forEach(dataSetParamDto -> contextData.put(dataSetParamDto.getParamName(), dataSetParamDto.getSampleItem()));
        return transform(contextData, dynSentence);
    }

    /**
     * 参数替换
     *
     * @param contextData 参数
     * @param dynSentence 待替换串
     * @return 替换后串
     */
    @Override
    public String transform(Map<String, Object> contextData, String dynSentence) {
        if (StringUtils.isBlank(dynSentence)) {
            return dynSentence;
        }
        if (dynSentence.contains("${")) {
            dynSentence = AnalysisUtil.resolveParams(contextData, dynSentence);
        }
        if (dynSentence.contains("${")) {
            throw new BusinessException("参数解析失败");
        }
        return dynSentence;
    }
}
